<?php
/*
 * Copyright (c) 2009 Tom Smith (tom@takeontom.com).
 * 
 * Distributed under the terms of the GNU Lesser General Public License.
 * 
 * ---------------------------------------------------------------------------------
 * 
 * This file is part of Seraph PHP Framework.
 *
 * Seraph PHP Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Seraph PHP Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Seraph PHP Framework.  If not, see <http://www.gnu.org/licenses/>.
*/


/**
 * Defines the URL of a view
 * 
 * @author Tom
 *
 */
class URLMap	{
	const UNKNOWN_TARGET_NAME = '_unknown';
	
	protected $URLs = array();
	
	protected $wildcardURLs = array();
	
	/**
	 * Add a URL and its target
	 * 
	 * @param $path
	 * @param $targetName
	 */
	public function addURL($path, $targetName)	{
		$path = $this->cleanPath($path);
		
		if (!$this->isValidURL($path))	{
			throw new RuntimeException('Invalid URL added to URLMap');
			return false;
		}
		
		$this->URLs[$path] = $targetName;
		
		//check for wild card character and add to wildcard array
		//makes searching for wildcards more efficient
		if ($this->URLContainsWildcard($path))	{
			$this->wildcardURLs[$path] = $targetName;
		}
	}
	
	/**
	 * Returns true/false whether the supplied URL is a wildcarded URL.
	 * 
	 * @param $URL
	 * @return bool
	 */
	public function URLContainsWildcard($URL)	{
		return (strpos($URL, '*') !== false);
	}
	
	/**
	 * Searches the supplied paths and returns the given target name.
	 * 
	 * If no target is found, will return UNKNOWN_TARGET_NAME
	 * 
	 * @param $path
	 * @return string
	 */
	public function getTargetNameFromPath($path)	{
		$path = $this->cleanPath($path);
		
		//first check for an exact match
		if (isset($this->URLs[$path]))	{
			return $this->URLs[$path];
		}
		
		//check for wild cards
		$targetFromWildcard = $this->getTargetNameFromWildcards($path);
		
		if ($targetFromWildcard)	{
			return $targetFromWildcard;
		}
		
		return self::UNKNOWN_TARGET_NAME;
	}
	
	/**
	 * Attemp find the target name using any wildcard URLs
	 * 
	 * @param string $path
	 * @return string
	 */
	protected function getTargetNameFromWildcards($path)	{
		//don't bother to do the check if there are no wildcard urls defined
		if (!count($this->wildcardURLs))	{
			return false;
		}
		
		//wildcard url looks like: /something/something/*
		//input url looks like: /something/something/wibble
		$found = array();
		foreach($this->wildcardURLs as $url => $target)	{
			//split the url at its wildcard character
			$urlPre = $this->cleanPath(substr($url, 0, strpos($url, '*')));
			
			if(strlen($urlPre))	{
				if (strpos($path, $urlPre) === 0)	{
					//match found - store for later
					$found[$url] = $target;
				}
			} else {
				$found[$url] = $target;
			}
		}
		
		if (!count($found))	{
			return false;
		}
		
		//go through the found matches and return the target for the longest
		//(and therefore most specific) url
		$largestURL = '';
		
		foreach($found as $url => $target)	{
			if (strlen($url) > strlen($largestURL))	{
				$largestURL = $url;
			}
		}
		return $found[$largestURL];
	}
	
	
	
	/**
	 * Cleans any junk from the path. Ensures that the paths
	 * are uniform in formatting (trailing slashes, etc.)
	 * 
	 * @param $path
	 * @return string
	 */
	public function cleanPath($path)	{
		$path = trim(trim($path), '/\\');
		
		return $path;
	}
	
	/**
	 * Validates a supplied URL
	 * @return bool
	 */
	public function isValidURL($path)	{
		$path = $this->cleanPath($path);
		
		$rule = '/^[a-z0-9-\.\/]*[*]?$/';
		
		$patternMatch = preg_match($rule, $path, $matches);
		
		if (!$patternMatch)	{
			return false;
		}
		
		return true;
	}
}
?>